package com.ruoyi.system.controller;

import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.EvSuggestion;
import com.ruoyi.system.service.IEvSuggestionService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.vo.SuggestionAiRequest;
import com.ruoyi.system.domain.vo.SuggestionAiExportRequest;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;

/**
 * 建议收集Controller
 * 
 * @author WJM
 * @date 2025-11-19
 */
@RestController
@RequestMapping("/system/suggestionOfCam")
public class EvSuggestionController extends BaseController
{
    private static final Logger log = LoggerFactory.getLogger(EvSuggestionController.class);

    private static final String DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions";

    @Autowired
    private IEvSuggestionService evSuggestionService;

    /**
     * 查询建议收集列表
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:list')")
    @GetMapping("/list")
    public TableDataInfo list(EvSuggestion evSuggestion)
    {
        startPage();
        List<EvSuggestion> list = evSuggestionService.selectEvSuggestionList(evSuggestion);
        return getDataTable(list);
    }

    /**
     * 导出建议收集列表
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:export')")
    @Log(title = "建议收集", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, EvSuggestion evSuggestion)
    {
        List<EvSuggestion> list = evSuggestionService.selectEvSuggestionList(evSuggestion);
        ExcelUtil<EvSuggestion> util = new ExcelUtil<EvSuggestion>(EvSuggestion.class);
        util.exportExcel(response, list, "建议收集数据");
    }

    /**
     * 获取建议收集详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:query')")
    @GetMapping(value = "/{suggestionId}")
    public AjaxResult getInfo(@PathVariable("suggestionId") Long suggestionId)
    {
        return success(evSuggestionService.selectEvSuggestionBySuggestionId(suggestionId));
    }

    /**
     * 新增建议收集
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:add')")
    @Log(title = "建议收集", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody EvSuggestion evSuggestion)
    {
        return toAjax(evSuggestionService.insertEvSuggestion(evSuggestion));
    }

    /**
     * 修改建议收集
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:edit')")
    @Log(title = "建议收集", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody EvSuggestion evSuggestion)
    {
        return toAjax(evSuggestionService.updateEvSuggestion(evSuggestion));
    }

    /**
     * 删除建议收集
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:remove')")
    @Log(title = "建议收集", businessType = BusinessType.DELETE)
	@DeleteMapping("/{suggestionIds}")
    public AjaxResult remove(@PathVariable Long[] suggestionIds)
    {
        return toAjax(evSuggestionService.deleteEvSuggestionBySuggestionIds(suggestionIds));
    }

    /**
     * AI 分析建议
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:list')")
    @PostMapping("/ai/analyze")
    public AjaxResult analyze(@RequestBody SuggestionAiRequest request)
    {
        if (request == null || StringUtils.isBlank(request.getApiKey()))
        {
            return AjaxResult.error("请在高级选项中输入有效的 Deepseek API Key");
        }
        List<EvSuggestion> suggestions = evSuggestionService.selectEvSuggestionList(new EvSuggestion());
        if (suggestions.isEmpty())
        {
            return AjaxResult.error("暂无建议数据，无法进行分析");
        }
        suggestions.sort(Comparator.comparing(EvSuggestion::getCreateTime,
                Comparator.nullsLast(Date::compareTo)).reversed());
        int limit = Math.max(1, Math.min(request.getMaxRecords() == null ? 20 : request.getMaxRecords(), suggestions.size()));
        List<EvSuggestion> limited = new ArrayList<>(suggestions.subList(0, limit));
        String summaryContext = buildSuggestionContext(limited, request.getPrompt());
        String model = StringUtils.defaultIfBlank(request.getModel(), "deepseek-chat");
        double temperature = request.getTemperature() == null ? 0.3D : request.getTemperature();
        try
        {
            String analysis = callDeepseek(model, request.getApiKey(), temperature, summaryContext);
            String sanitized = sanitizeAnalysisText(analysis);
            return AjaxResult.success("分析成功", sanitized);
        }
        catch (Exception ex)
        {
            log.error("调用 Deepseek 失败: {}", ex.getMessage());
            return AjaxResult.error("调用 Deepseek 失败：" + ex.getMessage());
        }
    }

    /**
     * 导出 AI 分析文档
     */
    @PreAuthorize("@ss.hasPermi('system:suggestionOfCam:list')")
    @PostMapping("/ai/exportDoc")
    public void exportAnalysisDoc(@RequestBody SuggestionAiExportRequest request, HttpServletResponse response)
    {
        if (request == null || StringUtils.isBlank(request.getContent()))
        {
            throw new IllegalArgumentException("AI 分析内容为空，无法导出");
        }
        writeAnalysisDocx(response, request.getContent());
    }

    private String buildSuggestionContext(List<EvSuggestion> suggestions, String extraPrompt)
    {
        StringBuilder builder = new StringBuilder();
        builder.append("以下是来自校园建议收集系统的最新反馈，请从满意度、主题分布、风险事项和改进建议等角度给出可执行的管理建议。\n");
        builder.append("输出要求：使用清晰的中文段落或有序编号（如 1.、2.、3.），不要使用 Markdown 符号（#、*、-、+、反引号等），也不要输出代码块。\n");
        if (StringUtils.isNotBlank(extraPrompt))
        {
            builder.append("额外分析要求：").append(extraPrompt).append("\n");
        }
        builder.append("建议列表：\n");
        for (EvSuggestion suggestion : suggestions)
        {
            builder.append("- 标题：").append(StringUtils.defaultString(suggestion.getTitle(), "未填写")).append("\n")
                .append("  内容：").append(StringUtils.defaultString(suggestion.getContent(), "未填写")).append("\n")
                .append("  校区/学院：").append(StringUtils.defaultString(suggestion.getCampus(), "未填写")).append("\n")
                .append("  满意度：").append(suggestion.getSatisfyScore() == null ? "未提供" : suggestion.getSatisfyScore())
                .append("\n")
                .append("  联系方式：").append(StringUtils.defaultIfBlank(suggestion.getContactInfo(), "匿名")).append("\n\n");
        }
        return builder.toString();
    }
    private String callDeepseek(String model, String apiKey, double temperature, String userContent) throws Exception
    {
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setBearerAuth(apiKey);

        List<Object> messages = new ArrayList<>();
        messages.add(new Message("system", "你是高校建议分析助手，请聚焦满意度、主题分布、风险事项以及可执行的改进建议输出条理清晰的中文分析。请仅使用普通段落或有序编号（例如 1.、2.、3.），禁止输出任何 Markdown 标记（如 #、*、-、+、反引号代码块等）。"));
        messages.add(new Message("user", userContent));

        DeepseekBody body = new DeepseekBody();
        body.setModel(model);
        body.setMessages(messages);
        body.setTemperature(temperature);

        HttpEntity<DeepseekBody> entity = new HttpEntity<>(body, headers);
        try
        {
            ResponseEntity<JsonNode> response = restTemplate.postForEntity(DEEPSEEK_API_URL, entity, JsonNode.class);
            JsonNode root = response.getBody();
            if (root == null)
            {
                throw new IllegalStateException("Deepseek 返回结果为空");
            }
            JsonNode choices = root.path("choices");
            if (!choices.isArray() || choices.size() == 0)
            {
                throw new IllegalStateException("未获取到分析结果");
            }
            JsonNode first = choices.get(0);
            String content = extractContent(first.path("message").path("content"));
            if (StringUtils.isBlank(content))
            {
                content = extractContent(first.path("text"));
            }
            if (StringUtils.isBlank(content))
            {
                content = extractContent(first.path("delta").path("content"));
            }
            if (StringUtils.isBlank(content))
            {
                log.warn("Deepseek返回内容为空：{}", first.toString());
                throw new IllegalStateException("AI 未返回任何文本，请稍后再试");
            }
            return content;
        }
        catch (HttpStatusCodeException ex)
        {
            String message = ex.getResponseBodyAsString();
            if (StringUtils.isBlank(message))
            {
                message = ex.getStatusText();
            }
            throw new RuntimeException(message);
        }
    }

    static class Message
    {
        private String role;
        private String content;

        Message(String role, String content)
        {
            this.role = role;
            this.content = content;
        }

        public String getRole()
        {
            return role;
        }

        public String getContent()
        {
            return content;
        }
    }

    static class DeepseekBody
    {
        private String model;
        private double temperature;
        private List<Object> messages;

        public String getModel()
        {
            return model;
        }

        public void setModel(String model)
        {
            this.model = model;
        }

        public double getTemperature()
        {
            return temperature;
        }

        public void setTemperature(double temperature)
        {
            this.temperature = temperature;
        }

        public List<Object> getMessages()
        {
            return messages;
        }

        public void setMessages(List<Object> messages)
        {
            this.messages = messages;
        }
    }

    private String sanitizeAnalysisText(String content)
    {
        if (StringUtils.isBlank(content))
        {
            return content;
        }
        String normalized = content.replace("\r\n", "\n");
        String[] lines = normalized.split("\n", -1);
        StringBuilder builder = new StringBuilder();
        for (String rawLine : lines)
        {
            if (StringUtils.isBlank(rawLine))
            {
                builder.append('\n');
                continue;
            }
            String line = rawLine;
            line = line.replaceFirst("^\\s*#+\\s*", "");
            line = line.replaceFirst("^\\s*[-*+]{1,}\\s*", "• ");
            line = line.replaceAll("\\*\\*(.*?)\\*\\*", "$1");
            line = line.replaceAll("\\*(.*?)\\*", "$1");
            line = line.replaceAll("#(?=\\d)", "");
            line = line.replaceAll("\\s+#\\s+", " ");
            builder.append(line.trim()).append('\n');
        }
        String cleaned = builder.toString().replaceAll("(\\n\\s*){3,}", "\n\n").trim();
        return cleaned;
    }

    private void writeAnalysisDocx(HttpServletResponse response, String content)
    {
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        String fileName = "suggestion-analysis-" + System.currentTimeMillis() + ".docx";
        try (XWPFDocument document = new XWPFDocument(); OutputStream outputStream = response.getOutputStream())
        {
            String encodedName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replace("+", "%20");
            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName);
            String sanitized = sanitizeAnalysisText(content);
            String normalized = StringUtils.defaultString(sanitized, "").replace("\r\n", "\n");
            String[] lines = normalized.split("\n", -1);
            for (String line : lines)
            {
                XWPFParagraph paragraph = document.createParagraph();
                paragraph.setSpacingAfterLines(150);
                XWPFRun run = paragraph.createRun();
                run.setFontSize(12);
                run.setText(StringUtils.defaultString(line, ""));
            }
            document.write(outputStream);
            outputStream.flush();
        }
        catch (Exception ex)
        {
            log.error("导出 AI 分析 docx 失败", ex);
            throw new RuntimeException("导出 AI 分析文档失败，请稍后重试");
        }
    }

    private String extractContent(JsonNode node)
    {
        if (node == null || node.isMissingNode() || node.isNull())
        {
            return null;
        }
        if (node.isTextual())
        {
            return node.asText();
        }
        if (node.isArray())
        {
            StringBuilder sb = new StringBuilder();
            for (JsonNode child : node)
            {
                String text = extractContent(child);
                if (StringUtils.isNotBlank(text))
                {
                    sb.append(text);
                    if (!text.endsWith("\n"))
                    {
                        sb.append('\n');
                    }
                }
            }
            return sb.toString().trim();
        }
        if (node.isObject())
        {
            JsonNode textNode = node.path("text");
            if (!textNode.isMissingNode())
            {
                return extractContent(textNode);
            }
        }
        return node.asText();
    }
}
